package user

import (
	"context"
	"fmt"
	"gitee.com/bobo-rs/idea-space-framework/enums"
	"gitee.com/bobo-rs/idea-space-framework/framework/model"
	"gitee.com/bobo-rs/idea-space-framework/pkg/core/models"
	"gitee.com/bobo-rs/idea-space-framework/pkg/core/services/jwt"
	"gitee.com/bobo-rs/idea-space-framework/pkg/core/services/login"
	"gitee.com/bobo-rs/idea-space-framework/pkg/exception"
	jwtHandler "gitee.com/bobo-rs/idea-space-framework/pkg/jwt"
	"gitee.com/bobo-rs/idea-space-framework/pkg/utils"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/util/grand"
	"github.com/gogf/gf/v2/util/guid"
)

// Login 账户密码或手机号快速认证登录
func (u *sUser) Login(ctx context.Context, in model.UserOauthLoginInput) (*model.UserOauthLoginOutput, error) {
	var (
		loginOauth  = login.New()
		safeAccount = in.Account // 安全账户名
		beforeParam = models.LoginValidateBeforeItem{
			Account:  in.Account,
			Sign:     in.Sign,
			IsRemove: true,
			Pwd:      in.Pwd,
			Mobile:   in.Mobile,
			Oauth:    in.Oauth,
		}
	)
	// 登录前置认证服务
	err := loginOauth.ValidateBefore(ctx, beforeParam)
	if err != nil {
		return nil, exception.NewCode(enums.ErrorLoginErrLock, err.Error())
	}

	// 后置处理
	defer func() {
		if err != nil {
			// 记录错误次数
			_ = loginOauth.IncrAccountLockNum(ctx, safeAccount)
		} else {
			// 登录成功-移除锁定
			_ = loginOauth.RemoveAccountLock(ctx, safeAccount)
		}
	}()

	// 解析用户登录认证参数
	parse, err := loginOauth.ParseLoginParam(ctx, beforeParam)
	if err != nil {
		return nil, err
	}
	// 重置安全账户-手机号或账户
	safeAccount = parse.Account

	// 登录处理
	detail, err := u.processLoginOauth(ctx, in, parse)
	if err != nil {
		return nil, err
	}

	// 后置用户信息验证
	afterDetail, err := u.UserOauthValidateAfter(ctx, *detail)
	if err != nil {
		return nil, err
	}

	// 后置处理登录成功信息，例如：记录登录日志、次数、设备信息
	oauthAfter, err := u.AfterUserOauth(ctx, afterDetail)
	if err != nil {
		return nil, err
	}
	return &model.UserOauthLoginOutput{
		UserOauthLoginItem: *oauthAfter,
	}, nil
}

// AfterUserOauth 后置操作-登录认证处理
func (u *sUser) AfterUserOauth(ctx context.Context, afterDetail *model.UserOauthAfterValidateItem) (*model.UserOauthLoginItem, error) {
	item := &model.UserOauthLoginItem{
		Status: afterDetail.Status,
	}
	tokenInfo, err := jwt.New(ctx).CreateToken(jwtHandler.AccountDetail{
		Uid:      afterDetail.User.Id,
		Account:  afterDetail.Account,
		Nickname: afterDetail.Nickname,
	})
	if err != nil {
		return nil, gerror.Wrapf(err, `登录失败%s`, err.Error())
	}
	// Token信息
	item.TokenItem = tokenInfo

	// 记录登录设备
	err = u.ProcessUserLoginAfter(ctx, model.UserLoginAfterItem{
		UserOauthAfterValidateItem: *afterDetail,
		UserOauthLoginItem: model.UserOauthLoginItem{
			TokenItem: tokenInfo,
			Status:    afterDetail.Status,
		},
	})
	if err != nil {
		return nil, err
	}
	return item, nil
}

// UserOauthValidateAfter 用户登录认证后置规则验证
func (u *sUser) UserOauthValidateAfter(ctx context.Context, detail model.UserOauthLoginDetailItem) (*model.UserOauthAfterValidateItem, error) {
	if enums.UserStatus(detail.User.Status) != enums.UserStatusOk {
		return nil, fmt.Errorf(`登录失败，账户%s`, enums.UserStatus(detail.User.Status).Fmt())
	}
	// 读取设备信息
	device, err := u.ProcessLoginUserDevice(ctx, detail.Id)
	if err != nil {
		return nil, err
	}
	// 是否新设备，用户状态是正常且是新设备，才重置
	if detail.Status == enums.UserLoginStatusOk && device.IsNewDevice == true {
		detail.Status = enums.UserLoginStatusND
	}
	return &model.UserOauthAfterValidateItem{
		UserOauthLoginDetailItem: detail,
		UserDeviceLoginAfterItem: *device,
	}, nil
}

// processNewUserDetail 处理并创建新用户消息
func (u *sUser) processNewUserDetail(ctx context.Context, item *model.UserSaveUserDetailItem) {
	// 自动生成账户
	item.Account = utils.NewAccount()
	// 注册账户IP
	item.RegIp = ghttp.RequestFromCtx(ctx).GetClientIp()
	item.LoginIp = item.RegIp
	item.PwdSalt = grand.S(6)
	// 用户唯一值
	item.UniqueId = guid.S([]byte(item.Account), []byte(item.Mobile))
}

// processLoginOauth 认证登录-账户、手机号等登录处理
func (u *sUser) processLoginOauth(ctx context.Context, in model.UserOauthLoginInput, parse *models.LoginParseParamItem) (detail *model.UserOauthLoginDetailItem, err error) {
	// 按场景登录
	switch in.Oauth {
	case enums.UserOauthAccount:
		// 账户登录
		detail, err = u.ValidateAccountLogin(ctx, model.UserOauthAccountLoginItem{
			Account: in.Account,
			Pwd:     parse.Pwd,
		})
	case enums.UserOauthSmsCaptcha:
		// 短信验证码登录
		detail, err = u.ValidateSmsCaptchaLogin(ctx, model.UserOauthSmsLoginItem{
			Code: in.Code,
			UserOauthSendSmsCaptchaItem: model.UserOauthSendSmsCaptchaItem{
				Mobile: parse.Mobile,
			},
		})
	default:
		err = gerror.New(`登录场景不存在`)
	}
	return
}
